﻿Namespace Flows

    Public Interface IMetisFlowNode
        Inherits IMetisCommonEntity

        ReadOnly Property HasChildren As Boolean
    End Interface


    Public Class MetisFlow
        Implements IMetisEntity, IMetisFlowNode, System.IComparable(Of IMetisFlowNode), System.ComponentModel.IEditableObject, IMetisExecutable

        Private _ID As Integer
        Private _Name As String
        Private _Annotation As String
        Private _Parent As MetisFlow

        Private _BackupName As String
        Private _BackupAnnotation As String
        Private _BackupParent As MetisFlow

        Private _IsEditMode As Boolean = False

        Private WithEvents _Children As MetisFlowList
        Private _MetisCore As MetisCore

        Protected _LoadState As MetisLoadState = MetisLoadState.NewDefinition
        Protected _LastUpdate As Date
        Protected _CreatedOn As Date
        Protected _ModifiedOn As Date
        Protected _IsModified As Boolean = False


        Public Event Changed(ByVal sender As IMetisEntity) Implements IMetisEntity.Changed
        Public Event Loaded(ByVal sender As IMetisEntity) Implements IMetisEntity.Loaded
        Public Event Progress(ByVal sender As IMetisEntity, ByVal Progress As MetisProgressEventArgs) Implements IMetisEntity.Progress
        Public Event Saved(ByVal sender As IMetisEntity) Implements IMetisEntity.Saved
        Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
        Public Event ChildListChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ListChangedEventArgs)

        Private Sub HandleChildListChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ListChangedEventArgs) Handles _Children.ListChanged
            If e.ListChangedType = System.ComponentModel.ListChangedType.ItemAdded OrElse _
               e.ListChangedType = System.ComponentModel.ListChangedType.ItemDeleted OrElse _
               e.ListChangedType = System.ComponentModel.ListChangedType.ItemMoved OrElse _
               e.ListChangedType = System.ComponentModel.ListChangedType.ItemChanged Then
                RaiseEvent ChildListChanged(sender, e)
            End If
        End Sub

        ''' <summary>Creates a new empty Flow instance.</summary>
        ''' <param name="MetisCore">Reference to the central management object of Metis that manages the access to the DB.</param>
        Sub New(ByVal MetisCore As Core.MetisCore)
            Me.New(MetisCore, MetisCore.GetTemporaryID, "", Nothing, "")
        End Sub

        ''' <summary>Creates a new Flow instance.</summary>
        ''' <param name="MetisCore">Reference to the central management object of Metis that manages the access to the DB.</param>
        ''' <param name="ID">DB-ID of the Flow</param>
        ''' <param name="Name">Name of the Flow</param>
        Sub New(ByVal MetisCore As Core.MetisCore, ByVal ID As Integer, ByVal Name As String)
            Me.New(MetisCore, ID, Name, Nothing, "")
        End Sub

        ''' <summary>Creates a new Flow instance.</summary>
        ''' <param name="MetisCore">Reference to the central management object of Metis that manages the access to the DB.</param>
        ''' <param name="ID">DB-ID of the Flow</param>
        ''' <param name="Name">Name of the Flow</param>
        ''' <param name="Parent">Reference to the parent Flow</param>
        ''' <remarks>Specifing a parent will not add the new Flow object to its child list!</remarks>
        Sub New(ByVal MetisCore As Core.MetisCore, ByVal ID As Integer, ByVal Name As String, ByVal Parent As MetisFlow)
            Me.New(MetisCore, ID, Name, Parent, "")
        End Sub

        ''' <summary>Creates a new Flow instance.</summary>
        ''' <param name="MetisCore">Reference to the central management object of Metis that manages the access to the DB.</param>
        ''' <param name="ID">DB-ID of the Flow</param>
        ''' <param name="Name">Name of the Flow</param>
        ''' <param name="Parent">Reference to the parent Flow</param>
        ''' <param name="Annotation">Any comment to that Flow.</param>
        ''' <remarks>Specifing a parent will not add the new Flow object to its child list!</remarks>
        Sub New(ByVal MetisCore As Core.MetisCore, ByVal ID As Integer, ByVal Name As String, ByVal Parent As MetisFlow, ByVal Annotation As String)
            _MetisCore = MetisCore
            _ID = ID
            _Name = Name
            _BackupName = _Name
            _Parent = Parent
            _BackupParent = _Parent
            _Annotation = Annotation
            _BackupAnnotation = _Annotation
            _Children = New MetisFlowList(MetisCore, Me)
        End Sub

        Public Shared Operator >(ByVal flow1 As MetisFlow, ByVal flow2 As MetisFlow) As Boolean
            Return (flow1 IsNot Nothing AndAlso flow2 IsNot Nothing AndAlso flow1.CompareTo(flow2) > 0)
        End Operator

        Public Shared Operator <(ByVal flow1 As MetisFlow, ByVal flow2 As MetisFlow) As Boolean
            Return (flow1 IsNot Nothing AndAlso flow2 IsNot Nothing AndAlso flow1.CompareTo(flow2) < 0)
        End Operator

        Public Shared Operator =(ByVal flow1 As MetisFlow, ByVal flow2 As MetisFlow) As Boolean
            Return (flow1 IsNot Nothing AndAlso flow2 IsNot Nothing AndAlso flow1.Equals(flow2))
        End Operator

        Public Shared Operator <>(ByVal flow1 As MetisFlow, ByVal flow2 As MetisFlow) As Boolean
            Return (flow1 Is Nothing OrElse flow2 Is Nothing OrElse Not flow1.Equals(flow2))
        End Operator

        Public ReadOnly Property ID As Integer Implements IMetisCommonEntity.ID
            Get
                Return _ID
            End Get
        End Property

        Public Property Name As String Implements IMetisCommonEntity.Name
            Get
                Return _Name
            End Get
            Set(ByVal value As String)
                If MetisCore.IsValidFieldName(value, 64) Then
                    Dim ParentList As MetisFlowList
                    If _Parent Is Nothing Then
                        ParentList = _MetisCore.Flows
                    Else
                        ParentList = _Parent.Children
                    End If

                    For Each item As IMetisFlowNode In ParentList
                        If Not Me.Equals(item) AndAlso value.Equals(item.Name, StringComparison.OrdinalIgnoreCase) Then
                            Throw New Exceptions.DublicateNameException(value)
                        End If
                    Next
                    _Name = value
                    If Not _IsEditMode AndAlso _Name <> _BackupName Then RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Name"))
                Else
                    Throw New Exceptions.InvalidNameException(value)
                End If
            End Set
        End Property

        Public Property Annotation As String Implements IMetisCommonEntity.Annotation
            Get
                Return _Annotation
            End Get
            Set(ByVal value As String)
                _Annotation = value
                If Not _IsEditMode AndAlso _Annotation <> _BackupAnnotation Then RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Annotation"))
            End Set
        End Property

        ''' <summary>Descendants of that Flow</summary>
        Public ReadOnly Property Children() As MetisFlowList
            Get
                Return _Children
            End Get
        End Property

        ''' <summary>Reference to the parent Flow</summary>
        Public Property Parent() As MetisFlow
            Get
                Return _Parent
            End Get
            Set(ByVal value As MetisFlow)
                _Parent = value
                If Not _IsEditMode Then RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Parent"))
            End Set
        End Property

        Public ReadOnly Property CreatedOn As Date Implements IMetisEntity.CreatedOn
            Get
                Return _CreatedOn
            End Get
        End Property

        Public ReadOnly Property IsModified As Boolean Implements IMetisEntity.IsModified
            Get
                Return (_Annotation <> _BackupAnnotation OrElse _Name <> _BackupName OrElse _ID < 0 OrElse _Parent <> _BackupParent)
            End Get
        End Property

        Public ReadOnly Property LastUpdate As Date Implements IMetisEntity.LastUpdate
            Get
                Return _LastUpdate
            End Get
        End Property

        Public ReadOnly Property LoadState As MetisLoadState Implements IMetisEntity.LoadState
            Get
                Return _LoadState
            End Get
        End Property

        Public ReadOnly Property ModifiedOn As Date Implements IMetisEntity.ModifiedOn
            Get
                Return _ModifiedOn
            End Get
        End Property

        Public Function GetNextID() As Integer Implements IMetisEntity.GetNextID
            _ID = _MetisCore.GetNextID
            RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("ID"))
            Return _ID
        End Function

        Public Sub Reload() Implements IMetisEntity.Reload

        End Sub

        Public Sub Save() Implements IMetisEntity.Save

        End Sub

        ''' <summary>Delete the Flow from DB.</summary>
        ''' <remarks>The Flow will also be removed from its parent child-list.</remarks>
        Public Sub Drop()
            Dim tmpStr As String = String.Format("DELETE FROM dam_flows WHERE flow_id={0}", _ID)
            Dim OraCmd As New OracleCommand(tmpStr, _MetisCore.Connection)
            OraCmd.ExecuteNonQuery()
            If _Parent IsNot Nothing Then
                _Parent.Children.Remove(Me)
            Else
                _MetisCore.Namespaces.Remove(Me)
            End If

        End Sub

        Public Sub Execute() Implements IMetisExecutable.Execute

        End Sub

        Public Overrides Function Equals(ByVal obj As Object) As Boolean
            If TypeOf obj Is MetisFlow AndAlso DirectCast(obj, MetisFlow).ID = _ID Then
                Return True
            Else
                Return MyBase.Equals(obj)
            End If
        End Function

        Public ReadOnly Property HasChildren As Boolean Implements IMetisFlowNode.HasChildren
            Get
                Return _Children.Count > 0
            End Get
        End Property

        Public Sub Move(ByVal TargetParentFlow As MetisFlow)
            Try
                Me.BeginEdit()

                Dim SrcParentChilds As Core.Flows.MetisFlowList
                If Me.Parent IsNot Nothing Then
                    SrcParentChilds = Me.Parent.Children
                Else
                    SrcParentChilds = _MetisCore.Flows
                End If

                SrcParentChilds.Remove(Me)
                If TargetParentFlow IsNot Nothing Then
                    TargetParentFlow.Children.Add(Me)
                Else
                    _MetisCore.Flows.Add(Me)
                End If

            Catch ex As Core.Exceptions.MetisNameException
                Me.CancelEdit()
                Throw ex
            Finally
                Me.EndEdit()
            End Try
        End Sub

        ''' <summary>Start Edit-Mode</summary>
        ''' <remarks>No <see cref="PropertyChanged"/>-Events will be raised while in edit mode.</remarks>
        Public Sub BeginEdit() Implements System.ComponentModel.IEditableObject.BeginEdit
            _IsEditMode = True
        End Sub

        ''' <summary>End Edit-Mode and reset properties to their former values.</summary>
        Public Sub CancelEdit() Implements System.ComponentModel.IEditableObject.CancelEdit
            If _IsEditMode Then
                _IsEditMode = False
                _Annotation = _BackupAnnotation
                _Name = _BackupName
                _Parent = _BackupParent
            End If
        End Sub

        ''' <summary>End Edit-Mode</summary>
        ''' <remarks>The Namespace will be saved to the DB afterwards.</remarks>
        Public Sub EndEdit() Implements System.ComponentModel.IEditableObject.EndEdit
            If _IsEditMode Then
                _IsEditMode = False
                Save()
            End If
        End Sub

        Public Function CompareTo(ByVal other As IMetisFlowNode) As Integer Implements System.IComparable(Of IMetisFlowNode).CompareTo
            Return String.Compare(_Name, other.Name, True)
        End Function

        Public Function CompareTo1(ByVal other As IMetisCommonEntity) As Integer Implements System.IComparable(Of IMetisCommonEntity).CompareTo
            Return Me.CompareTo(other)
        End Function
    End Class
End Namespace

